/* preview-image.vala
 *
 * Copyright (C) 2010  Richard Talbot-Watkins
 * Copyright (C) 2010  Dave Jeffery
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Authors:
 *  Richard Talbot-Watkins <richtw1@gmail.com>
 * 	Dave Jeffery <david.richard.jeffery@gmail.com>
 */

using Gtk;
using Cairo;

/**
 * The PreviewImage widget shows a preview of the sprites contained in
 * the current sprite file. 
 *
 * The image is stretched horizontally to MODE5 aspect ratio and scaled
 * by 200%.
 *
 * @author Dave Jeffery <david.richard.jeffery@gmail.com>
 * @version 2010.1216
 * @since 0.1
 */
private class MonsterDesigner.PreviewImage : DrawingArea {
	/**
	 * The size of one RGB24 pixel in bytes.
	 * 
	 * Used to work out the "stride" of the preview images' ImageSurface.
	 */
	private const int RGB24_SIZE = 4;

	/**
	 * Sprite data.
	 */
	private SpriteData sprite_data;

	/**
	 * Palette data.
	 */
	private PaletteData palette_data;

	/**
	 * Constructor for the PreviewImage widget.
	 *
	 * @param sprite_data height of sprite data in row_height units
	 * @param palette_data the palette used to display the sprite_data
	 * @param background_colour Cairo RGB value currently used as background
	 */ 
	public PreviewImage (SpriteData sprite_data, PaletteData palette_data) {
		this.sprite_data = sprite_data;
		this.palette_data = palette_data;

		palette_data.changed.connect (redraw_canvas);
		sprite_data.changed.connect (redraw_canvas);
	}

	/**
	 * Expose event handler. 
	 *
	 * The expose event is emitted when the 
	 * widget is asked to (re)paint itself.
	 * 
	 * @return false to pass signal to the default handler
	 */
	public override bool expose_event (Gdk.EventExpose event) {
		var cr = Gdk.cairo_create (this.window);
		cr.rectangle (event.area.x, event.area.y,
						event.area.width, event.area.height);
		cr.clip ();
		draw (cr);
		return false;
	}

	/**
	 * This method is called when the widget wants to repaint 
	 * itself.
	 */
	private void redraw_canvas () {
		if (this.window == null) {
			return;
		}

		set_size_request (103, sprite_data.rows * sprite_data.ROW_HEIGHT * 2);

		unowned Gdk.Region region = this.window.get_clip_region ();
		this.window.invalidate_region (region, true);
		this.window.process_updates (true);
	}

	/**
	 * Draws the widget using the Cairo graphics library.
	 *
	 * The Context is first filled with the current background colour. The
	 * background colour is always BBC Micro logical colour 0.
	 *
	 * The sprite data is placed onto an ImageSurface. The ImageSurface
	 * is then placed on a Pattern that applies a scale matrix transform
	 * using the fast, non anti-aliasing filter. The Pattern is then
	 * painted onto the background-coloured Context.
	 *
	 * @param cr Cairo context to draw onto
	 */
	private void draw (Context cr) {
		var background_colour = palette_data.logical_to_cairo (0);

		cr.save ();
		cr.set_source_rgb (background_colour.red, 
							background_colour.green,
							background_colour.blue);
		cr.rectangle (0, 0, this.allocation.width, this.allocation.height);
		cr.fill ();

		var cairo_surface = new ImageSurface.for_data (
								sprite_data.get_as_rgb24 (palette_data), 
								Format.RGB24, 
								sprite_data.SPRITE_WIDTH, 
								sprite_data.rows * sprite_data.ROW_HEIGHT, 
								sprite_data.SPRITE_WIDTH * RGB24_SIZE);
		var pattern = new Pattern.for_surface (cairo_surface);
		pattern.set_matrix (Matrix (0.25, 0, 0, 0.5, 1, 1));
		pattern.set_filter (Filter.FAST);
		cr.set_source (pattern);

		cr.paint();
		cr.restore();
	}
}
